﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Drawing;
using System.IO;
using System.Text;
using System.Xml;
using CalcSharp.Core;
using CalcSharp.Core.Containers;
using CalcSharp.Core.IO;
using System.Windows.Forms;
using CalcSharp.Ui;

namespace CalcSharp
{
    sealed class Loaders
    {
        private Loaders() { } 
        public static ASet LoadSet(Stream Src, string[] param, out long mem)
        {
            List<double> result = new List<double>();
            string tmp;
            if (param[0].ToUpper().EndsWith(".TXT"))
            {
                StreamReader sr = new StreamReader(Src);
                while (!sr.EndOfStream)
                {
                    tmp = sr.ReadLine();
                    result.Add(Convert.ToDouble(tmp));
                }
                mem = result.Count * 8;
                return SetFuncts.CreateSet(result);
            }
            else if (param[0].ToUpper().EndsWith(".XML"))
            {
                XmlDocument doc = new XmlDocument();
                string node = "item";
                if (param.Length > 1) node = param[1];
                doc.Load(Src);
                for (int i = 0; i < doc.ChildNodes.Count; i++)
                {
                    if (doc.ChildNodes[i].Name == node)
                    {
                        tmp = doc.ChildNodes[i].InnerText;
                        result.Add(Convert.ToDouble(tmp));
                    }
                }
                mem = result.Count * 8;
                return SetFuncts.CreateSet(result); ;
            }
            else if (param[0].ToUpper().EndsWith(".CSV"))
            {
                CSVParser cv;
                if (param.Length > 2) cv = new CSVParser(Src, param[2][0]);
                else cv = new CSVParser(Src, ';');
                int i;
                List<double> its = new List<double>();

                if (param[0].ToUpper() == "ROW")
                {
                    int rindex = Convert.ToInt32(param[1]);
                    for (i = 0; i < cv.Cols; i++) its.Add(Convert.ToDouble(cv[rindex, i]));
                }
                else if (param[0].ToUpper() == "COL")
                {
                    int cindex = Convert.ToInt32(param[1]);
                    for (i = 0; i < cv.Rows; i++) its.Add(Convert.ToDouble(cv[i, cindex]));
                }
                else throw new CSException("Invalid dimension. Dimension can be row or col");
                mem = its.Count * 8;
                return SetFuncts.CreateSet(result);
            }
            else throw new CSException("Unsuported file type.");
        }
        public static AMatrix LoadMatrix(Stream Src, string[] param, out long mem)
        {
            int i, j;
            AMatrix ret;
            CrawDriver rd;
            if (param[0].ToUpper().EndsWith(".CSV"))
            {
                CSVParser cv;
                if (param.Length > 1) cv = new CSVParser(Src, param[1][0]);
                else cv = new CSVParser(Src, ';');

                ret = MatrixFuncts.CreateMatrix(cv.Rows, cv.Cols);
                for (i = 0; i < cv.Rows; i++)
                {
                    for (j = 0; j < cv.Cols; j++)
                    {
                        ret[i, j] = Convert.ToDouble(cv[i, j]);
                    }
                }
                mem = ret.Rows * ret.Columns * (byte)Program.loaded.Mtrx_mem.StorageType;
                return ret;
            }
            else if (param[0].ToUpper().EndsWith(".XML"))
            {
                DataSet dt = new DataSet();
                dt.ReadXml(Src);
                if (dt.HasErrors) throw new CSException("XML loading error");
                ret = MatrixFuncts.CreateMatrix(dt.Tables[0].Rows.Count, dt.Tables[0].Columns.Count);
                for (i = 0; i < dt.Tables[0].Rows.Count; i++)
                {
                    for (j = 0; j < dt.Tables[0].Columns.Count; j++)
                    {
                        ret[i, j] = Convert.ToDouble(dt.Tables[0].Rows[i][j]);
                    }
                }
                mem = ret.Rows * ret.Columns * (byte)Program.loaded.Mtrx_mem.StorageType;
                return ret;
            }
            else if (param[0].ToUpper().EndsWith(".JPG") || param[0].ToUpper().EndsWith(".JPEG") || param[0].ToUpper().EndsWith(".GIF") || param[0].ToUpper().EndsWith(".PNG") || param[0].ToUpper().EndsWith(".TIF"))
            {
                Bitmap bmp = new Bitmap(Src);
                ret = MatrixFuncts.CreateMatrix(bmp.Height, bmp.Width);
                Color c;
                for (i = 0; i < bmp.Height; i++)
                {
                    for (j = 0; j < bmp.Width; j++)
                    {
                        c = bmp.GetPixel(j, i);
                        ret[i, j] = Convert.ToDouble(Int24.RGB2Int(c.R, c.G, c.B));
                    }
                }
                bmp.Dispose();
                bmp = null;
                mem = ret.Rows * ret.Columns * (byte)Program.loaded.Mtrx_mem.StorageType;
                return ret;
            }
            else if (param[0].ToUpper().EndsWith(".BMP"))
            {
                BMPDriver drv = new BMPDriver(Src);
                return drv.ReadBMPToMatrix(out mem, Program.loaded.Mtrx_mem.StorageType);
            }
            else if (param[0].ToUpper().EndsWith(".TGA"))
            {
                TGADriver tg = new TGADriver(Src);
                return tg.ReadToMatrix(Program.loaded.Mtrx_mem.StorageType, out mem);
            }
            else if (param[0].ToUpper().EndsWith(".CRAW"))
            {
                rd = new CrawDriver(Src);
                return rd.ReadMatrix(out mem, Program.loaded.Mtrx_mem.StorageType, true);
            }
            else if (param[0].ToUpper().EndsWith(".RAW"))
            {
                int w = (int)MiscFuncts.parsestr(param[1]);
                int h = (int)MiscFuncts.parsestr(param[2]);
                int bpp = (int)MiscFuncts.parsestr(param[3]);
                RawDriver r = new RawDriver(Src, w, h, bpp);
                return r.ReadMatrix(out mem, Program.loaded.Mtrx_mem.StorageType);
            }
            else if (param[0].ToUpper().EndsWith(".WDP"))
            {
                HDPhotoDriver hdr = new HDPhotoDriver(Src);
                return hdr.ReadMatrix(out mem, Program.loaded.Mtrx_mem.StorageType);
            }
            else throw new CSException("Unsuported file type.");
        }
        public static string LoadString(Stream Src, string[] param)
        {
            if (param[0].ToLower().EndsWith(".txt"))
            {
                StreamReader s = new StreamReader(Src);
                string ret = s.ReadToEnd();
                s.Close();
                return ret;
            }
            else if (param[0].ToLower().EndsWith(".rtf"))
            {
                RichTextBox rtb = new RichTextBox();
                StreamReader s = new StreamReader(Src);
                rtb.Rtf = s.ReadToEnd();
                s.Close();
                return rtb.Text;
            }
            else throw new CSException("Unsuported file type.");
        }
    }

    sealed class Savers
    {
        private Savers() { }
        public static void SaveMatrix(AMatrix src, string dest)
        {
            FileStream s;
            StreamWriter sw;
            StringBuilder file;
            CrawDriver rd;
            MemoryStream st;
            if (dest.EndsWith(".CSV", true, null))
            {
                file = new StringBuilder();
                StringBuilder row = new StringBuilder();
                int i, j;
                for (i = 0; i < src.Rows; i++)
                {
                    for (j = 0; j < src.Columns; j++)
                    {
                        row.Append(src[i, j]).Append(";");
                    }
                    file.Append(row + "\n");
                    row.Remove(0, row.Length - 1);
                }
                s = File.Create(dest);
                sw = new StreamWriter(s);
                sw.Write(file.ToString());
                sw.Close();
                s.Close();
            }   //MatrixFuncts.SaveMatrixAsCSV(src, dest);
            else if (dest.EndsWith(".xml", true, null))
            {
                file = new StringBuilder();
                file.Append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
                file.Append("<table>\n");
                for (int i = 0; i < src.Rows; i++)
                {
                    file.Append("\t<tr>\n\t\t");
                    for (int j = 0; j < src.Columns; j++)
                    {
                        file.Append("<td>");
                        file.Append(src[i, j].ToString());
                        file.Append("</td>");
                    }
                    file.Append("\n\t</tr>\n");
                }
                file.Append("</table>");
                s = File.Create(dest);
                sw = new StreamWriter(s);
                sw.Write(file.ToString());
                sw.Close();
                s.Close();
            }
            else if (dest.EndsWith(".xls", true, null))
            {
                //header
                StringBuilder sbTop = new StringBuilder();
                sbTop.Append("<html xmlns:o=\"urn:schemas-microsoft-com:office:office\" xmlns:x=\"urn:schemas-microsoft-com:office:excel\" ");
                sbTop.Append("xmlns=\"http://www.w3.org/TR/REC-html40\"><head><meta http-equiv=Content-Type content=\"text/html; charset=windows-1252\">");
                sbTop.Append("<meta name=ProgId content=Excel.Sheet><meta name=Generator content=\"Microsoft Excel 9\"><!--[if gte mso 9]>");
                sbTop.Append("<xml><x:ExcelWorkbook><x:ExcelWorksheets><x:ExcelWorksheet><x:Name>" + dest + "</x:Name><x:WorksheetOptions>");
                sbTop.Append("<x:Selected/><x:ProtectContents>False</x:ProtectContents><x:ProtectObjects>False</x:ProtectObjects>");
                sbTop.Append("<x:ProtectScenarios>False</x:ProtectScenarios></x:WorksheetOptions></x:ExcelWorksheet></x:ExcelWorksheets>");
                sbTop.Append("<x:ProtectStructure>False</x:ProtectStructure><x:ProtectWindows>False</x:ProtectWindows></x:ExcelWorkbook></xml>");
                sbTop.Append("<![endif]--></head><body><table>");
                string bottom = "</table></body></html>";
                file = new StringBuilder();
                if (src.Columns > 255) throw new Exception("Excell can only handle tables which have less rows than 255");
                for (int i = 0; i < src.Rows; i++)
                {
                    file.Append("<tr>");
                    for (int j = 0; j < src.Columns; j++)
                    {
                        file.Append("<td>");
                        file.Append(src[i, j].ToString());
                        file.Append("</td>");
                    }
                    file.Append("</tr>");
                }
                s = File.Create(dest);
                sw = new StreamWriter(s);
                sw.Write(sbTop.ToString());
                sw.Write(file.ToString());
                sw.Write(bottom);
                sw.Close();
                s.Close();
            }
            else if (dest.EndsWith(".bmp", true, null))
            {
                BMPDriver drv = new BMPDriver(File.Create(dest));
                drv.SaveMatrixToBMP(src);
            }
            else if (dest.EndsWith(".craw", true, null))
            {
                rd = new CrawDriver(File.Create(dest));
                rd.WriteMatrix(src, MtrxStorageType.tint24, true);
            }
            else if (dest.EndsWith(".raw", true, null))
            {
                RawDriver r = new RawDriver(File.Create(dest), 1, 1, 1);
                r.WriteMatrix(src);
            }
            else throw new CSException("Incorrect file extension. File extension must be bmp, xml, xls or csv");
            sw = null;
            s = null;
            file = null;
        }
        public static void SaveSet(ASet src, string dest)
        {
            TextWriter tw;
            int i;
            if (dest.ToUpper().EndsWith(".TXT"))
            {
                tw = File.CreateText(dest);
                for (i = 0; i < src.Count; i++) { tw.WriteLine(src[i].ToString()); }
                tw.Close();
            }
            else if (dest.ToUpper().EndsWith(".XML"))
            {
                tw = File.CreateText(dest);
                tw.WriteLine("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
                tw.WriteLine("<set>\n");
                for (i = 0; i < src.Count; i++) { tw.WriteLine("\t<item>" + src[i].ToString() + "</item>\n"); }
                tw.WriteLine("</set>");
                tw.Close();
            }
            else throw new CSException("Invalid file type. File type can be xml or txt");


        }
    }

    sealed class LoadSaveUI
    {
        private LoadSaveUI() { }
        public static void Load(string[] param)
        {
            int op = -1;
            string dest = param[1];
            string src = param[2];
            long memreq;
            string[] parampass = new string[param.Length -2];
            for (int i = 2; i < param.Length; i++) parampass[i - 2] = param[i];
            if (dest.IndexOf('#') == 0) op = 0;
            else if (dest.IndexOf('@') == 0) op = 1;
            else if (dest.IndexOf('~') == 0) op = 2;
            else throw new CSException("Destination must be a set, string or a matrix");

            switch (op)
            {
                case 0:
                    Program.loaded.Mtrx_mem[dest] = Loaders.LoadMatrix(MiscFuncts.MakeStream(src), parampass, out memreq);
                    Program.ConsoleForm.ForegroundColor = CalcSharp.Properties.Settings.Default.console_textok;
                    Program.ConsoleForm.WriteLine(" "+dest+" uses "+ConsoleUI.DFileSize(memreq)+" Memory");
                    Program.ConsoleForm.ForegroundColor = CalcSharp.Properties.Settings.Default.console_color;
                    break;
                case 1:
                    Program.loaded.Set_mem[dest] = Loaders.LoadSet(MiscFuncts.MakeStream(src), parampass, out memreq);
                    Program.ConsoleForm.ForegroundColor = CalcSharp.Properties.Settings.Default.console_textok;
                    Program.ConsoleForm.WriteLine(" " + dest + " uses " + ConsoleUI.DFileSize(memreq) + " Memory");
                    Program.ConsoleForm.ForegroundColor = CalcSharp.Properties.Settings.Default.console_color;
                    break;
                case 2:
                    Program.loaded.String_mem[dest] = Loaders.LoadString(MiscFuncts.MakeStream(src), parampass);
                    break;
                default:
                    throw new CSException("Invalid destination");
            }
        }
        public static void Save(string[] param)
        {
            int op = -1;
            string src = param[1];
            string dest = param[2];
            if (src.IndexOf('#') == 0) op = 0;
            else if (src.IndexOf('@') == 0) op = 1;
            else throw new CSException("Source must be a set or a matrix");

            switch (op)
            {
                case 0:
                    Savers.SaveMatrix(Program.loaded.Mtrx_mem[src], dest);
                    break;
                case 1:
                    Savers.SaveSet(Program.loaded.Set_mem[src], dest);
                    break;
                default:
                    throw new CSException("Invalid source");
            }
        }
    }
}
